#pragma once
#include "TubeTruckTypes.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>

namespace TTP {

   class Socket {
   protected:

      static Socket * sock_inst;
      bool connected;
      Address addr;
      int sock;

      Socket(const Socket& s);

      inline Socket() : sock(-1), connected(false) { 
         sock_init();
      }

      void sock_init() {
         int hops = 4;

         if(-1 == setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops,sizeof(hops))){
            throw msg_exception(strerror(hops));
         }
      }

      void _disconnect();

      void _recv(std::vector<byte>& data); 

   public:

      inline Address getDestAddress() { return addr; }

      inline bool isConnected() { return connected; }

      inline void disconnect() { _disconnect(); }

      inline int getSock() {
         if(sock < 0) throw msg_exception("Getting invalid sock");
         return sock;
      }

      inline static Socket* get() {
         if(!sock_inst) sock_inst = new Socket();
         return sock_inst;
      }

      inline ~Socket() {
         close(sock);
         sock = -1;
         sock_inst = NULL;
      }

      void connect(const Address &a); 

      void send(const std::vector<byte> & data); 

      void select(std::vector<byte>& data); 

      static pthread_mutex_t lock;
   };

   Socket * Socket::sock_inst = 0;
   pthread_mutex_t Socket::lock = PTHREAD_MUTEX_INITIALIZER;
}
